package com.smedi.ismedi.constructionproject.core.port.adapter.persistence.repository.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.smedi.ismedi.authority.starter.util.VerifyHelper;
import com.smedi.ismedi.constructionproject.core.domain.aggregatemodel.ProjectAssignment;
import com.smedi.ismedi.constructionproject.core.domain.aggregatemodel.dto.ProjectAssignmentQuery;
import com.smedi.ismedi.constructionproject.core.domain.repository.ProjectAssignmentRepository;
import com.smedi.ismedi.constructionproject.core.port.adapter.persistence.model.ProjectAssignmentEntity;
import com.smedi.ismedi.constructionproject.core.port.adapter.persistence.mybatis.mapper.ProjectAssignmentMapper;
import com.smedi.ismedi.constructionproject.core.port.adapter.restful.convert.AdapterConverter;
import com.smedi.ismedi.database.starter.annotation.SkipSqlPermission;
import com.smedi.ismedi.web.starter.util.DozerUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Repository;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author: xulinjun
 * @Date: 2021-6-18 15:55
 */
@Slf4j
@Repository
@AllArgsConstructor
public class ProjectAssignmentRepositoryImpl extends ServiceImpl<ProjectAssignmentMapper, ProjectAssignmentEntity> implements ProjectAssignmentRepository, IService<ProjectAssignmentEntity> {
    private final DozerUtil dozerUtil;
    private final AdapterConverter adapterConverter;
    private final VerifyHelper verifyHelper;

    @Override
    public ProjectAssignment selectByProjectAssignmentId(Long projectAssignmentId) {
        ProjectAssignmentEntity row = this.getBaseMapper().selectById(projectAssignmentId);
        if (row != null) {
            return dozerUtil.convertor(row, ProjectAssignment.class);
        } else {
            return null;
        }
    }

    @Override
    public ProjectAssignment doInsert(ProjectAssignment projectAssignment) {
        ProjectAssignmentEntity projectAssignmentEntity = dozerUtil.convertor(projectAssignment, ProjectAssignmentEntity.class);
        this.getBaseMapper().insert(projectAssignmentEntity);
        return dozerUtil.convertor(projectAssignmentEntity, ProjectAssignment.class);
    }

    @Override
    public ProjectAssignment doUpdate(ProjectAssignment projectAssignment) {
        ProjectAssignmentEntity projectAssignmentEntity = dozerUtil.convertor(projectAssignment, ProjectAssignmentEntity.class);
        this.getBaseMapper().updateById(projectAssignmentEntity);
        return dozerUtil.convertor(projectAssignmentEntity, ProjectAssignment.class);
    }

    @Override
    public int selectCountByPersonIdAndProjectIdAndProjectOrganizationId(Long personId, Long projectId, Long projectOrganizationId) {
        QueryWrapper<ProjectAssignmentEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("project_id", projectId)
                .eq("project_organization_id", projectOrganizationId)
                .eq("person_id", personId);
        return this.getBaseMapper().selectCount(wrapper);
    }

    @Override
    public void doDelete(Long projectAssignmentId) {
        this.getBaseMapper().deleteById(projectAssignmentId);
    }

    @Override
    public List<Long> selectPersonIdsByProjectId(Long projectId) {
        QueryWrapper<ProjectAssignmentEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("project_id", projectId);

        List<ProjectAssignmentEntity> list = this.getBaseMapper().selectList(wrapper);
        List<Long> personIds = new ArrayList<>();
        list.forEach(projectAssignment -> {
            if (projectAssignment.getProjectId() != null) {
                personIds.add(projectAssignment.getPersonId());
            }
        });

        return personIds;
    }

    @Override
    @SkipSqlPermission
    public List<Long> selectPersonIdsByProjectIdNoToken(Long projectId) {
        LambdaQueryWrapper<ProjectAssignmentEntity> wrapper = new LambdaQueryWrapper<>();

        wrapper.eq(ProjectAssignmentEntity::getProjectId, projectId);
        List<ProjectAssignmentEntity> list = this.getBaseMapper().selectList(wrapper);

        return list.stream().map(ProjectAssignmentEntity::getPersonId).collect(Collectors.toList());
    }

    @Override
    public List<ProjectAssignment> selectProjectAssignmentsByPersonId(Long personId) {
        QueryWrapper<ProjectAssignmentEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("person_id", personId).orderByAsc("id");

        List<ProjectAssignmentEntity> list = this.getBaseMapper().selectList(wrapper);
        return dozerUtil.convertor(list, ProjectAssignment.class);
    }

    @Override
    public List<ProjectAssignment> selectProjectAssignmentsByPersonIds(List<Long> personIds) {
        QueryWrapper<ProjectAssignmentEntity> wrapper = new QueryWrapper<>();
        wrapper.in("person_id", personIds).orderByAsc("id");

        List<ProjectAssignmentEntity> list = this.getBaseMapper().selectList(wrapper);
        return dozerUtil.convertor(list, ProjectAssignment.class);
    }

    @Override
    @SkipSqlPermission
    public List<ProjectAssignment> selectProjectAssignmentsByPersonIdSkipSql(Long personId) {
        LambdaQueryWrapper<ProjectAssignmentEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ProjectAssignmentEntity::getPersonId, personId);
        wrapper.orderByAsc(ProjectAssignmentEntity::getId);

        List<ProjectAssignmentEntity> list = this.getBaseMapper().selectList(wrapper);
        return dozerUtil.convertor(list, ProjectAssignment.class);
    }

    @Override
    public void doDeleteByPersonIdAndProjectId(Long personId, Long projectId) {
        QueryWrapper<ProjectAssignmentEntity> wrapper = new QueryWrapper();
        wrapper.eq("person_id", personId);
        wrapper.eq("project_id", projectId);

        this.getBaseMapper().delete(wrapper);
    }

    @Override
    public void doDeleteByPersonId(Long personId) {
        QueryWrapper<ProjectAssignmentEntity> wrapper = new QueryWrapper();
        wrapper.eq("person_id", personId);
        this.getBaseMapper().delete(wrapper);
    }

    @Override
    public int selectCountByProjectOrganizationId(Long projectOrganizationId) {
        QueryWrapper<ProjectAssignmentEntity> wrapper = new QueryWrapper();
        wrapper.eq("project_organization_id", projectOrganizationId);

        return this.getBaseMapper().selectCount(wrapper);
    }

    @Override
    public void doDeleteByProjectId(Long projectId) {
        QueryWrapper<ProjectAssignmentEntity> wrapper = new QueryWrapper();
        wrapper.eq("project_id", projectId);

        this.getBaseMapper().delete(wrapper);
    }

    @Override
    public List<ProjectAssignment> selectProjectAssignmentByProjectOrganizationId(Long projectOrganizationId) {
        QueryWrapper<ProjectAssignmentEntity> wrapper = new QueryWrapper();
        wrapper.eq("project_organization_id", projectOrganizationId);

        return dozerUtil.convertor(this.getBaseMapper().selectList(wrapper), ProjectAssignment.class);
    }

    @Override
    public List<ProjectAssignment> selectByProjectId(Long projectId) {
        QueryWrapper<ProjectAssignmentEntity> wrapper = new QueryWrapper();
        wrapper.eq("project_id", projectId);

        return dozerUtil.convertor(this.getBaseMapper().selectList(wrapper), ProjectAssignment.class);
    }

    @Override
    public void saveProjectAssignment(ProjectAssignment projectAssignment) {
        ProjectAssignmentEntity projectAssignmentEntity = adapterConverter.projectAssignmentToProjectAssignmentEntity(projectAssignment);
        if (!verifyHelper.isAvailable(projectAssignmentEntity.getId())) {
            this.getBaseMapper().insert(projectAssignmentEntity);
        }
        if (verifyHelper.isAvailable(projectAssignmentEntity.getId())) {
            this.getBaseMapper().updateById(projectAssignmentEntity);
        }
    }

    @Override
    @SkipSqlPermission
    public List<ProjectAssignment> getProjectAssignmentList(ProjectAssignmentQuery projectAssignmentQuery) {
        LambdaQueryWrapper<ProjectAssignmentEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();

        lambdaQueryWrapper.in(CollectionUtils.isNotEmpty(projectAssignmentQuery.getProjectIds()), ProjectAssignmentEntity::getProjectId, projectAssignmentQuery.getProjectIds());
        lambdaQueryWrapper.in(CollectionUtils.isNotEmpty(projectAssignmentQuery.getPersonIds()), ProjectAssignmentEntity::getPersonId, projectAssignmentQuery.getPersonIds());
        lambdaQueryWrapper.in(CollectionUtils.isNotEmpty(projectAssignmentQuery.getProjectOrganizationIds()), ProjectAssignmentEntity::getProjectOrganizationId, projectAssignmentQuery.getProjectOrganizationIds());

        lambdaQueryWrapper.eq(ObjectUtils.isNotNull(projectAssignmentQuery.getProjectId()), ProjectAssignmentEntity::getProjectId, projectAssignmentQuery.getProjectId());
        lambdaQueryWrapper.in(ObjectUtils.isNotNull(projectAssignmentQuery.getPersonId()), ProjectAssignmentEntity::getProjectId, projectAssignmentQuery.getPersonId());
        lambdaQueryWrapper.in(ObjectUtils.isNotNull(projectAssignmentQuery.getProjectOrganizationId()), ProjectAssignmentEntity::getProjectId, projectAssignmentQuery.getProjectOrganizationId());
        lambdaQueryWrapper.like(StringUtils.isNotBlank(projectAssignmentQuery.getProjectJobLike()), ProjectAssignmentEntity::getProjectJob, projectAssignmentQuery.getProjectJobLike());


        List<ProjectAssignmentEntity> projectAssignmentEntities = this.getBaseMapper().selectList(lambdaQueryWrapper);
        if (CollectionUtils.isNotEmpty(projectAssignmentEntities)) {
            if (StringUtils.isNotBlank(projectAssignmentQuery.getProjectJob())) {
                projectAssignmentEntities = projectAssignmentEntities.stream().filter(projectAssignmentEntity -> projectAssignmentEntity.getProjectJob() != null && Arrays.asList(projectAssignmentEntity.getProjectJob().split(",")).contains(projectAssignmentQuery.getProjectJob())).collect(Collectors.toList());
            }
            if (CollectionUtils.isNotEmpty(projectAssignmentQuery.getProjectJobs())) {
                projectAssignmentEntities = projectAssignmentEntities.stream().filter(projectAssignmentEntity -> projectAssignmentEntity.getProjectJob() != null && org.apache.commons.collections.CollectionUtils.containsAny(Arrays.asList(projectAssignmentEntity.getProjectJob().split(",")), projectAssignmentQuery.getProjectJobs())).collect(Collectors.toList());
            }
        }

        return dozerUtil.convertor(projectAssignmentEntities, ProjectAssignment.class);
    }

    @Override
    @SkipSqlPermission
    public List<ProjectAssignment> getProjectAssignmentListWithoutToken(ProjectAssignmentQuery projectAssignmentQuery) {
        LambdaQueryWrapper<ProjectAssignmentEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();

        lambdaQueryWrapper.in(CollectionUtils.isNotEmpty(projectAssignmentQuery.getProjectIds()), ProjectAssignmentEntity::getProjectId, projectAssignmentQuery.getProjectIds());
        lambdaQueryWrapper.in(CollectionUtils.isNotEmpty(projectAssignmentQuery.getPersonIds()), ProjectAssignmentEntity::getPersonId, projectAssignmentQuery.getPersonIds());
        lambdaQueryWrapper.in(CollectionUtils.isNotEmpty(projectAssignmentQuery.getProjectOrganizationIds()), ProjectAssignmentEntity::getProjectOrganizationId, projectAssignmentQuery.getProjectOrganizationIds());

        lambdaQueryWrapper.in(ObjectUtils.isNotNull(projectAssignmentQuery.getProjectId()), ProjectAssignmentEntity::getProjectId, projectAssignmentQuery.getProjectId());
        lambdaQueryWrapper.in(ObjectUtils.isNotNull(projectAssignmentQuery.getPersonId()), ProjectAssignmentEntity::getProjectId, projectAssignmentQuery.getPersonId());
        lambdaQueryWrapper.in(ObjectUtils.isNotNull(projectAssignmentQuery.getProjectOrganizationId()), ProjectAssignmentEntity::getProjectId, projectAssignmentQuery.getProjectOrganizationId());

        List<ProjectAssignmentEntity> projectAssignmentEntities = this.getBaseMapper().selectList(lambdaQueryWrapper);

        return dozerUtil.convertor(projectAssignmentEntities, ProjectAssignment.class);
    }
}
